#include <iostream>
#include <math.h>
#include <string.h>
#include <stdio.h>

using namespace std;

// Include GLEW
#include <GL/glew.h>

// Include GLFW
#include <GL/glfw.h>

// Include GLUT
#include <GL/glut.h>

// Include GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtx/norm.hpp>
#include <glm/gtx/rotate_vector.hpp>

using namespace glm;

#include "shader.hpp"
#include "text2D.hpp"

#include "map.hpp"
#include "grid.hpp"

#ifndef GRAPHICSENGINE_HPP
#define GRAPHICSENGINE_HPP

#define MAX_CAMERA_HEIGHT 500
#define MIN_CAMERA_HEIGHT 0.2

#define R 6371

#define uint unsigned int

class Camera
{
public:
    mat4 *View;
    float *FPS;

    vec3 view;
    vec3 position;
    vec3 up;

    float cameraSpeedX;
    float cameraSpeedY;

    float height;

    int lastScroll;

    void setPosition(vec3 _position);

    vec3 getView();
    vec3 getPosition();

    virtual void cameraBH();
    virtual float getHeight();
    virtual vec2 getMapCords();
    virtual void updateLastScroll();
};

class FreeCamera : public Camera
{
private:
    const int centerX;
    const int centerY;

    float mouseSpeed;

    void rotateView(float angle, float x, float y, float z);
public:
    FreeCamera(mat4 *_View, float *_FPS);

    void cameraBH();
    float getHeight();
};

class LockCamera : public Camera
{
public:
    LockCamera(mat4 *_View, float *_FPS);

    void cameraBH();
    float getHeight();
};

class SphereLockCamera : public Camera
{
    vec2 mapPos;
public:
    SphereLockCamera(mat4 *_View, float *_FPS);

    void cameraBH();
    float getHeight();
    vec2 getMapCords();
};

class SphereFreeCamera : public Camera
{
    const int centerX;
    const int centerY;

    float mouseSpeed;
public:
    SphereFreeCamera(mat4 *_View, float *_FPS);

    void cameraBH();
    float getHeight();
    vec2 getMapCords();
};

class GraphicEngine
{
private:
    char cPosiotion[30];

    //------- FPS -------
    int frameCount;
    float fps;
    char cfps[20];
    uint currentTime, previousTime, timeInterval;

    void initCalculateFPS();
    void calculateFPS();

    //------- Auto LOD -------
    bool autoLODon;
    char cAutoLOD[20];
    int autoLODvar;         //what LOD autoLOD use
    vec2 lastCamCords;

    void initAutoLOD();
    void autoLOD(MapsCon *maps, Camera *cam);

    //------- GLFW -------
    mat4 Projection;
    mat4 View;

    GLuint VertexArrayID;

    int initWinodw();

    //------- Camera -------
    Camera **cams;
    short camera;

    void initCams(mat4 *_View, float *_FPS);

    short view;     //what view we are using map or sphere

    //------- Buttons -------
    bool autoLoadButton;
    void buttons(MapsCon *maps);

    bool CButtonState;
    bool cameraChangeButton();

    bool VButtonState;
    bool viewChangeButton(MapsCon *maps, Grid *grid);
public:
    GraphicEngine();

    void graphicEngineLoop();
};

#endif
